home *** CD-ROM | disk | FTP | other *** search
/ Amiga Games Extra 1996 September / Amiga Games Extra CD-ROM 9-1996.iso / userbox / publicdomain / vim-4.2 / src / gui_athena.c < prev    next >
C/C++ Source or Header  |  1996-06-09  |  27KB  |  1,034 lines

  1. /* vi:set ts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved            by Bram Moolenaar
  4.  *                                GUI/Motif support by Robert Webb
  5.  *                                Athena port by Bill Foster
  6.  *
  7.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  8.  * Do ":help credits" in Vim to see a list of people who contributed.
  9.  */
  10.  
  11. #include <X11/StringDefs.h>
  12. #include <X11/Intrinsic.h>
  13. #include <X11/Xaw/Paned.h>
  14. #include <X11/Xaw/Form.h>
  15. #include <X11/Xaw/SimpleMenu.h>
  16. #include <X11/Xaw/MenuButton.h>
  17. #include <X11/Xaw/SmeBSB.h>
  18. #include <X11/Xaw/Box.h>
  19.  
  20. #include "vim.h"
  21. #include "globals.h"
  22. #include "proto.h"
  23. #include "option.h"
  24. #include "ops.h"
  25. #include "gui_at_sb.h"
  26.  
  27. #define puller_width    19
  28. #define puller_height    19
  29.  
  30. static char puller_bits[] =
  31. {
  32.     0x00,0x00,0xf8,0x00,0x00,0xf8,0xf8,0x7f,0xf8,0x04,0x80,0xf8,0x04,0x80,0xf9,
  33.     0x84,0x81,0xf9,0x84,0x83,0xf9,0x84,0x87,0xf9,0x84,0x8f,0xf9,0x84,0x8f,0xf9,
  34.     0x84,0x87,0xf9,0x84,0x83,0xf9,0x84,0x81,0xf9,0x04,0x80,0xf9,0x04,0x80,0xf9,
  35.     0xf8,0xff,0xf9,0xf0,0x7f,0xf8,0x00,0x00,0xf8,0x00,0x00,0xf8
  36. };
  37.  
  38. extern Widget vimShell;
  39.  
  40. static Widget vimPanes;
  41. static Widget vimForm = (Widget)NULL;
  42. static Widget textArea;
  43. static Widget scrollbarBox[3];        /* Left, right & bottom scrollbar boxes */
  44. static Widget bottomScrollbar;            /* Bottom scrollbar */
  45. static Widget leftBottomScrollFiller;    /* Left filler for bottom scrollbar */
  46. static Widget rightBottomScrollFiller;    /* Right filler for bottom scrollbar */
  47. static Widget leftScrollbarFiller;        /* Filler for left scrollbar */
  48. static Widget rightScrollbarFiller;        /* Filler for right scrollbar */
  49. static Widget menuBar;
  50.  
  51. static void gui_athena_scroll_cb_jump   __ARGS((Widget, XtPointer, XtPointer));
  52. static void gui_athena_scroll_cb_scroll __ARGS((Widget, XtPointer, XtPointer));
  53. static void gui_athena_reorder_menus    __ARGS((void));
  54. static void    gui_athena_pullright_action __ARGS((Widget, XEvent *, String *,
  55.                                                 Cardinal *));
  56.  
  57. static XtActionsRec        pullAction = { "menu-pullright",
  58.                                 (XtActionProc)gui_athena_pullright_action };
  59. static XtTranslations    parentTrans, menuTrans;
  60. static Pixmap            pullerBitmap;
  61.  
  62. /*
  63.  * Scrollbar callback (XtNjumpProc) for when the scrollbar is dragged with the
  64.  * left or middle mouse button.
  65.  */
  66.     static void
  67. gui_athena_scroll_cb_jump(w, client_data, call_data)
  68.     Widget        w;
  69.     XtPointer    client_data, call_data;
  70. {
  71.     char_u        bytes[4 + sizeof(long_u)];
  72.     WIN            *wp;
  73.     GuiScrollbar *sb;
  74.     int            sb_num;
  75.     int         i;
  76.     int         byte_count;
  77.     long_u        value;
  78.  
  79.     gui.dragged_sb = SB_NONE;
  80.     for (i = 0; i <= SB_BOTTOM; i++)
  81.         if (XtParent(w) == scrollbarBox[i])
  82.         {
  83.             gui.dragged_sb = i;
  84.             break;
  85.         }
  86.  
  87.     switch (gui.dragged_sb)
  88.     {
  89.         case SB_LEFT:
  90.         case SB_RIGHT:
  91.             gui.dragged_wp = (WIN *)client_data;
  92.             sb_num = 0;
  93.             wp = firstwin;
  94.             for ( ; wp != gui.dragged_wp && wp != NULL; wp = wp->w_next)
  95.                 sb_num++;
  96.  
  97.             if (gui.dragged_wp == NULL)
  98.                 return;
  99.  
  100.             sb = &wp->w_scrollbar;
  101.  
  102.             value = *((float *)call_data) * (float)sb->max + 0.5;
  103.             ++value;                        /* range is 1 to line_count */
  104.             sb->value = value;
  105.             
  106.             bytes[0] = CSI;
  107.             bytes[1] = KS_SCROLLBAR;
  108.             bytes[2] = K_FILLER;
  109.             bytes[3] = (char_u)sb_num;
  110.             byte_count = 4;
  111.             break;
  112.  
  113.         case SB_BOTTOM:
  114.                                             /* why not use sb->max? */
  115.             value = *((float *)call_data) *
  116.                                     (float)(gui_get_max_horiz_scroll()) + 0.5;
  117.             bytes[0] = CSI;
  118.             bytes[1] = KS_HORIZ_SCROLLBAR;
  119.             bytes[2] = K_FILLER;
  120.             byte_count = 3;
  121.             break;
  122.  
  123.         case SB_NONE:
  124.         default:
  125.             return;
  126.     }
  127.  
  128.     add_long_to_buf(value, bytes + byte_count);
  129.     add_to_input_buf(bytes, byte_count + sizeof(long_u));
  130. }
  131.  
  132. /*
  133.  * Scrollbar callback (XtNscrollProc) for paging up or down with the left or
  134.  * right mouse buttons.
  135.  */
  136.     static void
  137. gui_athena_scroll_cb_scroll(w, client_data, call_data)
  138.     Widget        w;
  139.     XtPointer    client_data, call_data;
  140. {
  141.     char_u        bytes[4 + sizeof(long_u)];
  142.     WIN            *wp;
  143.     GuiScrollbar *sb;
  144.     int            sb_num;
  145.     int         i;
  146.     int         byte_count;
  147.     long        value;
  148.     int            data = (int)call_data;
  149.  
  150.     for (i = 0; i <= SB_BOTTOM; i++)
  151.         if (XtParent(w) == scrollbarBox[i])
  152.         {
  153.             gui.dragged_sb = i;
  154.             break;
  155.         }
  156.  
  157.     switch (gui.dragged_sb)
  158.     {
  159.         case SB_LEFT:
  160.         case SB_RIGHT:
  161.             gui.dragged_wp = (WIN *)client_data;
  162.             sb_num = 0;
  163.             wp = firstwin;
  164.             for ( ; wp != gui.dragged_wp && wp != NULL; wp = wp->w_next)
  165.                 sb_num++;
  166.  
  167.             if (gui.dragged_wp == NULL)
  168.                 return;
  169.  
  170.             sb = &wp->w_scrollbar;
  171.             
  172.             if (sb->size > 5)
  173.                 i = sb->size - 2;        /* use two lines of context */
  174.             else
  175.                 i = sb->size;
  176.             switch (data)
  177.             {
  178.                 case  ONE_LINE_DATA: data = 1; break;
  179.                 case -ONE_LINE_DATA: data = -1; break;
  180.                 case  ONE_PAGE_DATA: data = i; break;
  181.                 case -ONE_PAGE_DATA: data = -i; break;
  182.                 case  END_PAGE_DATA: data = sb->max; break;
  183.                 case -END_PAGE_DATA: data = -sb->max; break;
  184.                             default: data = 0; break;
  185.             }
  186.             value = sb->value + data;
  187.             if (value > sb->max)
  188.                 value = sb->max;
  189.             else if (value < 1)            /* range is 1 to line_count */
  190.                 value = 1;
  191.  
  192.             bytes[0] = CSI;
  193.             bytes[1] = KS_SCROLLBAR;
  194.             bytes[2] = K_FILLER;
  195.             bytes[3] = (char_u)sb_num;
  196.             byte_count = 4;
  197.             break;
  198.  
  199.         case SB_BOTTOM:
  200.             if (data < -1)
  201.                 data = -(Columns - 5);
  202.             else if (data > 1)
  203.                 data = (Columns - 5);
  204.             value = curwin->w_leftcol + data;
  205.             if (value < 0)                /* range is 0 to max_col */
  206.                 value = 0;
  207.             else
  208.             {
  209.                 int max;
  210.                                         /* why not use sb->max here? */
  211.                 max = gui_get_max_horiz_scroll();
  212.                 if (value >= max)
  213.                     value = max;
  214.             }
  215.  
  216.             bytes[0] = CSI;
  217.             bytes[1] = KS_HORIZ_SCROLLBAR;
  218.             bytes[2] = K_FILLER;
  219.             byte_count = 3;
  220.             break;
  221.  
  222.         case SB_NONE:
  223.         default:
  224.             return;
  225.     }
  226.  
  227.     /*
  228.      * This type of scrolling doesn't move the thumb automatically so we need
  229.      * make sure the scrollbar still gets updated.
  230.      */
  231.     gui.dragged_sb = SB_NONE;
  232.  
  233.     add_long_to_buf((long_u)value, bytes + byte_count);
  234.     add_to_input_buf(bytes, byte_count + sizeof(long_u));
  235. }
  236.  
  237. /*
  238.  * Create all the Athena widgets necessary.
  239.  */
  240.     void
  241. gui_mch_create_widgets()
  242. {
  243.     Dimension    base_width, base_height;
  244.  
  245.     /*
  246.      * We don't have any borders handled internally by the textArea to worry
  247.      * about so only skip over the configured border width.
  248.      */
  249.     gui.border_offset = gui.border_width;
  250.  
  251.     base_width  = 2 * gui.border_offset;
  252.     base_height = 2 * gui.border_offset;
  253.  
  254.     XtInitializeWidgetClass(panedWidgetClass);
  255.     XtInitializeWidgetClass(simpleMenuWidgetClass);
  256.     XtInitializeWidgetClass(vim_scrollbarWidgetClass);
  257.     XtInitializeWidgetClass(labelWidgetClass);
  258.  
  259.     /* Panes for menu bar, middle stuff, and bottom scrollbar box */
  260.     vimPanes = XtVaCreateManagedWidget("vimPanes",
  261.         panedWidgetClass,    vimShell,
  262.         XtNorientation,        XtorientVertical,
  263.         NULL);
  264.  
  265.     /* The top menu bar */
  266.     menuBar = XtVaCreateManagedWidget("menuBar",
  267.         boxWidgetClass,            vimPanes,
  268.         XtNmin,                    gui.menu_height,
  269.         XtNborderWidth,            1,
  270.         XtNallowResize,            True,
  271.         XtNresizeToPreferred,    True,
  272.         XtNskipAdjust,            True,
  273.         XtNshowGrip,            False,
  274.         XtNforeground,            gui.menu_fg_pixel,
  275.         XtNbackground,            gui.menu_bg_pixel,
  276.         XtNborderColor,            gui.menu_fg_pixel,
  277.         NULL);
  278.  
  279.     /*
  280.      * Panes for the middle stuff (left scrollbar box, text area, and right
  281.      * scrollbar box.
  282.      */
  283.     vimForm = XtVaCreateManagedWidget("vimForm",
  284.         panedWidgetClass,        vimPanes,
  285.         XtNallowResize,            True,
  286.         XtNorientation,            XtorientHorizontal,
  287.         XtNborderWidth,            0,
  288.         XtNdefaultDistance,        0,
  289.         XtNshowGrip,            False,
  290.         NULL);
  291.  
  292.     /* Panes for the left window scrollbars. */
  293.     scrollbarBox[SB_LEFT] = XtVaCreateWidget("scrollBarBox",
  294.         panedWidgetClass,        vimForm,
  295.         XtNpreferredPaneSize,    gui.scrollbar_width,
  296.         XtNallowResize,            True,
  297.         XtNskipAdjust,            True,
  298.         XtNborderWidth,            1,
  299.         XtNshowGrip,            False,
  300.         XtNforeground,            gui.scroll_fg_pixel,
  301.         XtNbackground,            gui.scroll_fg_pixel,
  302.         XtNborderColor,            gui.scroll_fg_pixel,
  303.         NULL);
  304.  
  305.     /* The text area. */
  306.     textArea = XtVaCreateManagedWidget("textArea",
  307.         coreWidgetClass,        vimForm,
  308.         XtNallowResize,            True,
  309.         XtNshowGrip,            False,
  310.         XtNbackground,            gui.back_pixel,
  311.         XtNborderWidth,            0,
  312.         XtNheight,                Rows * gui.char_height + base_height,
  313.         XtNwidth,                Columns * gui.char_width + base_width,
  314.         NULL);
  315.  
  316.     /* Panes for the right window scrollbars. */
  317.     scrollbarBox[SB_RIGHT] = XtVaCreateWidget("scrollBarBox",
  318.         panedWidgetClass,        vimForm,
  319.         XtNpreferredPaneSize,    gui.scrollbar_width,
  320.         XtNallowResize,            True,
  321.         XtNskipAdjust,            True,
  322.         XtNborderWidth,            1,
  323.         XtNresizeToPreferred,    True,
  324.         XtNshowGrip,            False,
  325.         XtNforeground,            gui.scroll_fg_pixel,
  326.         XtNbackground,            gui.scroll_fg_pixel,
  327.         XtNborderColor,            gui.scroll_fg_pixel,
  328.         NULL);
  329.  
  330.     /* Panes for the bottom scrollbar and fillers on each side. */
  331.     scrollbarBox[SB_BOTTOM] = XtVaCreateWidget("scrollBarBox",
  332.         panedWidgetClass,        vimPanes,
  333.         XtNpreferredPaneSize,    gui.scrollbar_width,
  334.         XtNallowResize,            True,
  335.         XtNskipAdjust,            True,
  336.         XtNborderWidth,            1,
  337.         XtNresizeToPreferred,    True,
  338.         XtNshowGrip,            False,
  339.         XtNforeground,             gui.scroll_fg_pixel,
  340.         XtNbackground,             gui.scroll_fg_pixel,
  341.         XtNborderColor,            gui.scroll_fg_pixel,
  342.         XtNorientation,         XtorientHorizontal,
  343.         NULL);
  344.  
  345.     /* A filler for the gap on the left side of the bottom scrollbar. */
  346.     leftBottomScrollFiller = XtVaCreateManagedWidget("",
  347.         labelWidgetClass,    scrollbarBox[SB_BOTTOM],
  348.         XtNshowGrip,        False,
  349.         XtNresize,            False,
  350.         XtNborderWidth,        4,
  351.         XtNmin,                gui.scrollbar_width + 1,
  352.         XtNmax,                gui.scrollbar_width + 1,
  353.         XtNforeground,        gui.scroll_fg_pixel,
  354.         XtNbackground,        gui.scroll_fg_pixel,
  355.         XtNborderColor,        gui.scroll_fg_pixel,
  356.         NULL);
  357.  
  358.     /* The bottom scrollbar. */
  359.     bottomScrollbar = XtVaCreateManagedWidget("bottomScrollBar",
  360.         vim_scrollbarWidgetClass,    scrollbarBox[SB_BOTTOM],
  361.         XtNresizeToPreferred,    True,
  362.         XtNallowResize,            True,
  363.         XtNskipAdjust,            True,
  364.         XtNshowGrip,            False,
  365.         XtNorientation,            XtorientHorizontal,
  366.         XtNforeground,            gui.scroll_fg_pixel,
  367.         XtNbackground,            gui.scroll_bg_pixel,
  368.         NULL);
  369.  
  370.     XtAddCallback(bottomScrollbar, XtNjumpProc,
  371.             gui_athena_scroll_cb_jump, (XtPointer)NULL);
  372.     XtAddCallback(bottomScrollbar, XtNscrollProc,
  373.             gui_athena_scroll_cb_scroll, (XtPointer)NULL);
  374.  
  375.     vim_XawScrollbarSetThumb(bottomScrollbar, 0., 1., 0.);
  376.  
  377.     /* A filler for the gap on the right side of the bottom scrollbar. */
  378.     rightBottomScrollFiller = XtVaCreateManagedWidget("",
  379.         labelWidgetClass,    scrollbarBox[SB_BOTTOM],
  380.         XtNshowGrip,        False,
  381.         XtNresize,            False,
  382.         XtNborderWidth,        4,
  383.         XtNmin,                gui.scrollbar_width + 1,
  384.         XtNmax,                gui.scrollbar_width + 1,
  385.         XtNforeground,        gui.scroll_fg_pixel,
  386.         XtNbackground,        gui.scroll_fg_pixel,
  387.         NULL);
  388.  
  389.     /* A filler for the gap on the bottom of the left scrollbar. */
  390.     leftScrollbarFiller = XtVaCreateManagedWidget("",
  391.         labelWidgetClass,    scrollbarBox[SB_LEFT],
  392.         XtNshowGrip,        False,
  393.         XtNresize,            False,
  394.         XtNborderWidth,        4,
  395.         XtNmin,                gui.scrollbar_width + 1,
  396.         XtNmax,                gui.scrollbar_width + 1,
  397.         XtNforeground,        gui.scroll_fg_pixel,
  398.         XtNbackground,        gui.scroll_fg_pixel,
  399.         NULL);
  400.  
  401.     /* A filler for the gap on the bottom of the right scrollbar. */
  402.     rightScrollbarFiller = XtVaCreateManagedWidget("",
  403.         labelWidgetClass,    scrollbarBox[SB_RIGHT],
  404.         XtNshowGrip,        False,
  405.         XtNresize,            False,
  406.         XtNborderWidth,        4,
  407.         XtNmin,                gui.scrollbar_width + 1,
  408.         XtNmax,                gui.scrollbar_width + 1,
  409.         XtNforeground,        gui.scroll_fg_pixel,
  410.         XtNbackground,        gui.scroll_fg_pixel,
  411.         NULL);
  412.  
  413.     gui.num_scrollbars = 0;
  414.  
  415.     /*
  416.      * Text area callbacks
  417.      */
  418.     XtAddEventHandler(textArea, VisibilityChangeMask, FALSE,
  419.         gui_x11_visibility_cb, (XtPointer)0);
  420.  
  421.     XtAddEventHandler(textArea, ExposureMask, FALSE, gui_x11_expose_cb,
  422.         (XtPointer)0);
  423.  
  424.     XtAddEventHandler(textArea, StructureNotifyMask, FALSE,
  425.         gui_x11_resize_window_cb, (XtPointer)0);
  426.  
  427.     XtAddEventHandler(vimShell, FocusChangeMask, FALSE, gui_x11_focus_change_cb,
  428.         (XtPointer)0);
  429.  
  430.     XtAddEventHandler(vimPanes, KeyPressMask, FALSE, gui_x11_key_hit_cb,
  431.         (XtPointer)0);
  432.  
  433.     XtAddEventHandler(textArea, ButtonPressMask | ButtonReleaseMask |
  434.         ButtonMotionMask, FALSE, gui_x11_mouse_cb, (XtPointer)0);
  435.  
  436.     parentTrans = XtParseTranslationTable("<BtnMotion>: highlight() menu-pullright()");
  437.     menuTrans = XtParseTranslationTable("<LeaveWindow>: unhighlight() MenuPopdown()\n<BtnUp>: notify() unhighlight() MenuPopdown()\n<BtnMotion>: highlight()");
  438.  
  439.     XtAppAddActions(XtWidgetToApplicationContext(vimForm), &pullAction, 1);
  440.  
  441.     pullerBitmap = XCreateBitmapFromData(gui.dpy, DefaultRootWindow(gui.dpy),
  442.                             (char *)puller_bits, puller_width, puller_height);
  443. }
  444.  
  445.     int
  446. gui_mch_get_winsize()
  447. {
  448.     Dimension    base_width, base_height;
  449.     Dimension    total_width, total_height;
  450.     Dimension    left_width = 0, right_width = 0;
  451.     Dimension    bottom_height = 0, menu_height = 0;
  452.  
  453.     base_height = 2 * gui.border_offset;
  454.     base_width  = 2 * gui.border_offset;
  455.  
  456.     if (gui.which_scrollbars[SB_LEFT])
  457.         XtVaGetValues(scrollbarBox[SB_LEFT], XtNwidth, &left_width, NULL);
  458.  
  459.     if (gui.which_scrollbars[SB_RIGHT])
  460.         XtVaGetValues(scrollbarBox[SB_RIGHT], XtNwidth, &right_width, NULL);
  461.  
  462.     if (gui.which_scrollbars[SB_BOTTOM])
  463.         XtVaGetValues(scrollbarBox[SB_BOTTOM], XtNheight, &bottom_height, NULL);
  464.  
  465.     if (XtIsManaged(menuBar))
  466.         XtVaGetValues(menuBar, XtNheight, &menu_height, NULL);
  467.  
  468.     base_width  += left_width + right_width;
  469.     base_height += menu_height + bottom_height;
  470.  
  471.     XtVaGetValues(vimShell,
  472.         XtNheight, &total_height,
  473.         XtNwidth,  &total_width,
  474.         NULL);
  475.  
  476.     gui.num_rows = (total_height - base_height) / gui.char_height;
  477.     gui.num_cols = (total_width  - base_width)  / gui.char_width;
  478.  
  479.     Rows    = gui.num_rows;
  480.     Columns = gui.num_cols;
  481.     gui_reset_scroll_region();
  482.  
  483.     return OK;
  484. }
  485.  
  486.     void
  487. gui_mch_set_winsize()
  488. {
  489.     Dimension    left_width = 0, right_width = 0;
  490.     Dimension    bottom_height = 0, menu_height = 0;
  491.     Dimension    base_width, base_height;
  492.  
  493.     base_width  = 2 * gui.border_offset;
  494.     base_height = 2 * gui.border_offset;
  495.  
  496.     if (gui.which_scrollbars[SB_LEFT])
  497.         XtVaGetValues(scrollbarBox[SB_LEFT], XtNwidth, &left_width, NULL);
  498.  
  499.     if (gui.which_scrollbars[SB_RIGHT])
  500.         XtVaGetValues(scrollbarBox[SB_RIGHT], XtNwidth, &right_width, NULL);
  501.  
  502.     if (gui.which_scrollbars[SB_BOTTOM])
  503.         XtVaGetValues(scrollbarBox[SB_BOTTOM], XtNheight, &bottom_height, NULL);
  504.  
  505.     if (XtIsManaged(menuBar))
  506.         XtVaGetValues(menuBar, XtNheight, &menu_height, NULL);
  507.  
  508.     base_width  += left_width + right_width;
  509.     base_height += menu_height + bottom_height;
  510.  
  511.     XtVaSetValues(vimShell,
  512.         XtNwidthInc,   gui.char_width,
  513.         XtNheightInc,  gui.char_height,
  514.         XtNbaseWidth,  base_width,
  515.         XtNbaseHeight, base_height,
  516.         XtNminWidth,   base_width  + MIN_COLUMNS * gui.char_width,
  517.         XtNminHeight,  base_height + MIN_ROWS    * gui.char_height,
  518.         XtNwidth,       base_width  + Columns     * gui.char_width,
  519.         XtNheight,       base_height + Rows        * gui.char_height,
  520.         NULL);
  521. }
  522.  
  523. /*
  524.  * Menu stuff.
  525.  */
  526.  
  527.     void
  528. gui_mch_add_menu(menu, parent)
  529.     GuiMenu    *menu;
  530.     GuiMenu    *parent;
  531. {
  532.     char_u    *pullright_name;
  533.  
  534.     if (parent == NULL)
  535.     {
  536.         menu->id = XtVaCreateManagedWidget(menu->name,
  537.             menuButtonWidgetClass, menuBar,
  538.             XtNmenuName, menu->name,
  539.             XtNforeground, gui.menu_fg_pixel,
  540.             XtNbackground, gui.menu_bg_pixel,
  541.             NULL);
  542.  
  543.         menu->submenu_id = XtVaCreatePopupShell(menu->name,
  544.             simpleMenuWidgetClass, menu->id,
  545.             XtNforeground, gui.menu_fg_pixel,
  546.             XtNbackground, gui.menu_bg_pixel,
  547.             NULL);
  548.  
  549.         gui_athena_reorder_menus();
  550.     }
  551.     else
  552.     {
  553.         menu->id = XtVaCreateManagedWidget(menu->name,
  554.             smeBSBObjectClass, parent->submenu_id,
  555.             XtNforeground, gui.menu_fg_pixel,
  556.             XtNbackground, gui.menu_bg_pixel,
  557.             XtNrightMargin, puller_width,
  558.             XtNrightBitmap, pullerBitmap,
  559.  
  560.             NULL);
  561.         XtAddCallback(menu->id, XtNcallback, gui_x11_menu_cb,
  562.             (XtPointer)menu);
  563.  
  564.         pullright_name = strnsave(menu->name, strlen(menu->name) +
  565.                                                         strlen("-pullright"));
  566.         strcat(pullright_name, "-pullright");
  567.         menu->submenu_id = XtVaCreatePopupShell(pullright_name,
  568.             simpleMenuWidgetClass, parent->submenu_id,
  569.             XtNforeground, gui.menu_fg_pixel,
  570.             XtNbackground, gui.menu_bg_pixel,
  571.             XtNtranslations, menuTrans,
  572.             NULL);
  573.         vim_free(pullright_name);
  574.  
  575.         XtOverrideTranslations(parent->submenu_id, parentTrans);
  576.     }
  577. }
  578.  
  579.     void
  580. gui_mch_add_menu_item(menu, parent)
  581.     GuiMenu    *menu;
  582.     GuiMenu    *parent;
  583. {
  584.     menu->submenu_id = (Widget)0;
  585.     menu->id = XtVaCreateManagedWidget(menu->name,
  586.         smeBSBObjectClass, parent->submenu_id,
  587.         XtNforeground, gui.menu_fg_pixel,
  588.         XtNbackground, gui.menu_bg_pixel,
  589.         NULL);
  590.     XtAddCallback(menu->id, XtNcallback, gui_x11_menu_cb,
  591.         (XtPointer)menu);
  592. }
  593.  
  594. /*
  595.  * Destroy the machine specific menu widget.
  596.  */
  597.     void
  598. gui_mch_destroy_menu(menu)
  599.     GuiMenu    *menu;
  600. {
  601.     if (menu->id != (Widget)NULL)
  602.     {
  603.         /*
  604.          * This is a hack for the Athena simpleMenuWidget to keep it from
  605.          * getting a BadValue error when it's last child is destroyed. We
  606.          * check to see if this is the last child and if so, go ahead and
  607.          * delete the parent ahead of time. The parent will delete it's
  608.          * children like all good widgets do.
  609.          */
  610.         if (XtParent(menu->id) != menuBar)
  611.         {
  612.             int num_children;
  613.  
  614.             XtVaGetValues(XtParent(menu->id),
  615.                     XtNnumChildren, &num_children, NULL);
  616.             if (num_children <= 1)
  617.                 XtDestroyWidget(XtParent(menu->id));
  618.             else
  619.                 XtDestroyWidget(menu->id);
  620.         }
  621.         else
  622.             XtDestroyWidget(menu->id);
  623.         menu->id = (Widget)NULL;
  624.     }
  625. }
  626.  
  627. /*
  628.  * Reorder the menus so "Help" is the rightmost item on the menu.
  629.  */
  630.     static void
  631. gui_athena_reorder_menus()
  632. {
  633.     Widget    *children;
  634.     Widget  help_widget = (Widget)NULL;
  635.     int        num_children;
  636.     int        i;
  637.  
  638.     XtVaGetValues(menuBar,
  639.             XtNchildren,    &children,
  640.             XtNnumChildren, &num_children,
  641.             NULL);
  642.  
  643.     XtUnmanageChildren(children, num_children);
  644.  
  645.     for (i = 0; i < num_children - 1; i++)
  646.         if (help_widget == (Widget)NULL)
  647.         {
  648.             if (strcmp((char *)XtName(children[i]), "Help") == 0)
  649.             {
  650.                 help_widget = children[i];
  651.                 children[i] = children[i + 1];
  652.             }
  653.         }
  654.         else
  655.             children[i] = children[i + 1];
  656.  
  657.     if (help_widget != (Widget)NULL)
  658.         children[num_children - 1] = help_widget;
  659.  
  660.     XtManageChildren(children, num_children);
  661. }
  662.  
  663.  
  664. /*
  665.  * Scrollbar stuff:
  666.  */
  667.  
  668.     void
  669. gui_mch_create_which_components()
  670. {
  671.     static int prev_which_scrollbars[3] = {-1, -1, -1};
  672.     static int prev_menu_is_active = -1;
  673.  
  674.     int          i;
  675.     WIN          *wp;
  676.  
  677.     /*
  678.      * When removing the left/right scrollbar and creating the right/left
  679.      * scrollbar, we have to force a redraw (the size of the text area doesn't
  680.      * change).
  681.      */
  682.     if (prev_which_scrollbars[SB_LEFT] != gui.which_scrollbars[SB_LEFT] &&
  683.             prev_which_scrollbars[SB_RIGHT] != gui.which_scrollbars[SB_RIGHT])
  684.         must_redraw = CLEAR;
  685.  
  686.     gui_x11_use_resize_callback(textArea, FALSE);
  687.  
  688.     for (i = 0; i < 3; i++)
  689.     {
  690.         if (gui.which_scrollbars[i] != prev_which_scrollbars[i])
  691.         {
  692.             if (gui.which_scrollbars[i])
  693.             {
  694.                 switch (i)
  695.                 {
  696.                     /* When adding the left one, we need to reorder them all */
  697.                     case SB_LEFT:
  698.                         XtUnmanageChild(textArea);
  699.                         if (gui.which_scrollbars[SB_RIGHT])
  700.                             XtUnmanageChild(scrollbarBox[SB_RIGHT]);
  701.                         XtManageChild(scrollbarBox[SB_LEFT]);
  702.                         XtManageChild(textArea);
  703.                         if (gui.which_scrollbars[SB_RIGHT])
  704.                             XtManageChild(scrollbarBox[SB_RIGHT]);
  705.  
  706.                         /*
  707.                          * When adding at the left and we have a bottom
  708.                          * scrollbar, we need to reorder these too.
  709.                          */
  710.                         if (gui.which_scrollbars[SB_BOTTOM])
  711.                         {
  712.                             XtUnmanageChild(bottomScrollbar);
  713.                             if (gui.which_scrollbars[SB_RIGHT])
  714.                                 XtUnmanageChild(rightBottomScrollFiller);
  715.  
  716.                             XtManageChild(leftBottomScrollFiller);
  717.                             XtManageChild(bottomScrollbar);
  718.                             if (gui.which_scrollbars[SB_RIGHT])
  719.                                 XtManageChild(rightBottomScrollFiller);
  720.                         }
  721.                         break;
  722.  
  723.                     case SB_RIGHT:
  724.                         XtManageChild(rightBottomScrollFiller);
  725.                         XtManageChild(scrollbarBox[i]);
  726.                         break;
  727.  
  728.                     case SB_BOTTOM:
  729.                         /* Unmanage the bottom scrollbar and fillers */
  730.                         XtUnmanageChild(leftBottomScrollFiller);
  731.                         XtUnmanageChild(bottomScrollbar);
  732.                         XtUnmanageChild(rightBottomScrollFiller);
  733.  
  734.                         /*
  735.                          * Now manage the bottom scrollbar and fillers that
  736.                          * are supposed to be there.
  737.                          */
  738.                         if (gui.which_scrollbars[SB_LEFT])
  739.                             XtManageChild(leftBottomScrollFiller);
  740.                         XtManageChild(bottomScrollbar);
  741.                         if (gui.which_scrollbars[SB_RIGHT])
  742.                             XtManageChild(rightBottomScrollFiller);
  743.  
  744.                         XtManageChild(scrollbarBox[i]);
  745.                         break;
  746.                 }
  747.             }
  748.             else
  749.             {
  750.                 switch (i)
  751.                 {
  752.                     case SB_LEFT:
  753.                         XtUnmanageChild(leftBottomScrollFiller);
  754.                         break;
  755.  
  756.                     case SB_RIGHT:
  757.                         XtUnmanageChild(rightBottomScrollFiller);
  758.                         break;
  759.                 }
  760.                 XtUnmanageChild(scrollbarBox[i]);
  761.             }
  762.         }
  763.         if (gui.which_scrollbars[i] != prev_which_scrollbars[i])
  764.         {
  765.             if (i == SB_LEFT || i == SB_RIGHT)
  766.             {
  767.                 if (gui.which_scrollbars[i])
  768.                 {
  769.                     /* Scrollbar box has just appeared */
  770.                     gui.new_sb[i] = TRUE;
  771.                 }
  772.                 else if (prev_which_scrollbars[i] == TRUE)
  773.                 {
  774.                     /* Scrollbar box has just been deleted */
  775.                     for (wp = firstwin; wp != NULL; wp = wp->w_next)
  776.                         XtDestroyWidget(wp->w_scrollbar.id[i]);
  777.                 }
  778.             }
  779.         }
  780.         prev_which_scrollbars[i] = gui.which_scrollbars[i];
  781.     }
  782.  
  783.     if (gui.menu_is_active != prev_menu_is_active)
  784.     {
  785.         if (gui.menu_is_active)
  786.         {
  787.             XtUnmanageChild(menuBar);
  788.             XtUnmanageChild(vimForm);
  789.             if (gui.which_scrollbars[SB_BOTTOM])
  790.                 XtUnmanageChild(scrollbarBox[SB_BOTTOM]);
  791.  
  792.             XtManageChild(menuBar);
  793.             XtManageChild(vimForm);
  794.             if (gui.which_scrollbars[SB_BOTTOM])
  795.                 XtManageChild(scrollbarBox[SB_BOTTOM]);
  796.         }
  797.         else
  798.             XtUnmanageChild(menuBar);
  799.         prev_menu_is_active = gui.menu_is_active;
  800.     }
  801.  
  802.     gui_x11_use_resize_callback(textArea, TRUE);
  803.     if (vimForm != (Widget)NULL && XtIsRealized(vimForm))
  804.         gui_mch_set_winsize();
  805. }
  806.  
  807.  
  808. /*
  809.  * Vertical scrollbar stuff:
  810.  */
  811.     void
  812. gui_mch_update_scrollbars(worst_update, which_sb)
  813.     int        worst_update;
  814.     int        which_sb;        /* SB_LEFT or SB_RIGHT */
  815. {
  816.     WIN                *wp;
  817.     GuiScrollbar    *sb;
  818.     int                idx;
  819.     Dimension        h;        /* Height of scrollbar (in pixels) */
  820.     Dimension        y;        /* Coord of top of scrollbar (in pixels) */
  821.     int                tmp;
  822.     float            val = 0., size = 0.;
  823.  
  824.     if (worst_update >= SB_UPDATE_HEIGHT)
  825.     {
  826.         XawPanedSetRefigureMode(scrollbarBox[which_sb], False);
  827.         gui_x11_use_resize_callback(textArea, FALSE);
  828.     }
  829.  
  830.     /*
  831.      * This has to get cleared manually since Athena doesn't tell us when the
  832.      * draggin' stops.
  833.      */
  834.     gui.dragged_sb = SB_NONE;
  835.  
  836.     for (wp = firstwin, idx = 0; wp; wp = wp->w_next, idx++)
  837.     {
  838.         sb = &wp->w_scrollbar;
  839.         if (sb->update[which_sb] >= SB_UPDATE_VALUE)
  840.         {
  841.             val = (float)(sb->value - 1) / (float)sb->max;
  842.             size = (float)sb->size / (float)sb->max;
  843.         }
  844.         if (sb->update[which_sb] == SB_UPDATE_CREATE)
  845.         {
  846.             sb->id[which_sb] = XtVaCreateManagedWidget("scrollBar",
  847.                     vim_scrollbarWidgetClass, scrollbarBox[which_sb],
  848.                     XtNborderWidth, 1,
  849.                     XtNdefaultDistance, 0,
  850.                     XtNallowResize, True,
  851.                     XtNpreferredPaneSize, True,
  852.                     XtNresizeToPreferred, True,
  853.                     XtNskipAdjust, True,
  854.                     XtNorientation, XtorientVertical,
  855.                     XtNshowGrip, False,
  856.                     XtNforeground, gui.scroll_fg_pixel,
  857.                     XtNbackground, gui.scroll_bg_pixel,
  858.                     NULL);
  859.             XtAddCallback(sb->id[which_sb], XtNjumpProc,
  860.                 gui_athena_scroll_cb_jump, (XtPointer)wp);
  861.             XtAddCallback(sb->id[which_sb], XtNscrollProc,
  862.                 gui_athena_scroll_cb_scroll, (XtPointer)wp);
  863.         }
  864.         if (sb->update[which_sb] >= SB_UPDATE_HEIGHT)
  865.         {
  866.             h = sb->height * gui.char_height
  867.                     + sb->status_height * gui.char_height / 2;
  868.             y = wp->w_winpos * gui.char_height + gui.border_offset;
  869.  
  870.             if (wp == firstwin)
  871.             {
  872.                 /* Height of top scrollbar includes width of top border */
  873.                 h += gui.border_offset;
  874.             }
  875.             else
  876.             {
  877.                 /*
  878.                  * Height of other scrollbars includes half of status bar above
  879.                  */
  880.                 tmp = wp->w_prev->w_status_height * (gui.char_height + 1) / 2;
  881.                 h += tmp;
  882.                 y -= tmp;
  883.             }
  884.  
  885.             XtVaSetValues(sb->id[which_sb],
  886.                 XtNheight, h,
  887.                 XtNmin, h,
  888.                 XtNmax, h,
  889.                 XtNy, y,
  890.                 NULL);
  891.             vim_XawScrollbarSetThumb(sb->id[which_sb], val, size, 1.0);
  892.         }
  893.         else if (sb->update[which_sb] == SB_UPDATE_VALUE)
  894.         {
  895.             vim_XawScrollbarSetThumb(sb->id[which_sb], val, size, 1.0);
  896.         }
  897.         sb->update[which_sb] = SB_UPDATE_NOTHING;
  898.     }
  899.  
  900.     if (worst_update >= SB_UPDATE_HEIGHT)
  901.     {
  902.         if (worst_update >= SB_UPDATE_CREATE)
  903.             gui_mch_reorder_scrollbars(which_sb);
  904.         XawPanedSetRefigureMode(scrollbarBox[which_sb], True);
  905.         gui_x11_use_resize_callback(textArea, TRUE);
  906.     }
  907. }
  908.  
  909.     void
  910. gui_mch_reorder_scrollbars(which_sb)
  911.     int        which_sb;
  912. {
  913.     WIN        *wp;
  914.  
  915.     if (which_sb == SB_LEFT)
  916.         XtUnmanageChild(leftScrollbarFiller);
  917.     else
  918.         XtUnmanageChild(rightScrollbarFiller);
  919.  
  920.     for (wp = firstwin; wp != NULL; wp = wp->w_next)
  921.         if (wp->w_scrollbar.id[which_sb] != NULL)
  922.             XtUnmanageChild(wp->w_scrollbar.id[which_sb]);
  923.  
  924.     for (wp = firstwin; wp != NULL; wp = wp->w_next)
  925.         if (wp->w_scrollbar.id[which_sb] != NULL)
  926.             XtManageChild(wp->w_scrollbar.id[which_sb]);
  927.  
  928.     if (which_sb == SB_LEFT)
  929.         XtManageChild(leftScrollbarFiller);
  930.     else
  931.         XtManageChild(rightScrollbarFiller);
  932.  
  933. }
  934.  
  935.     void
  936. gui_mch_destroy_scrollbar(wp)
  937.     WIN        *wp;
  938. {
  939.     if (gui.which_scrollbars[SB_LEFT])
  940.         XtDestroyWidget(wp->w_scrollbar.id[SB_LEFT]);
  941.     if (gui.which_scrollbars[SB_RIGHT])
  942.         XtDestroyWidget(wp->w_scrollbar.id[SB_RIGHT]);
  943.     gui.num_scrollbars--;
  944. }
  945.  
  946.  
  947. /*
  948.  * Horizontal scrollbar stuff:
  949.  */
  950.     void
  951. gui_mch_update_horiz_scrollbar(value, size, max)
  952.     int        value;
  953.     int        size;
  954.     int        max;
  955. {
  956.     static int prev_value = -1, prev_size = -1, prev_max = -1;
  957.     float val, shown, maxval;
  958.  
  959.     if (value == prev_value && size == prev_size && max == prev_max)
  960.         return;
  961.  
  962.     prev_value = value;
  963.     prev_size = size;
  964.     prev_max = max;
  965.  
  966.     if (max == 1)            /* maximum is one more than maximal value */
  967.     {
  968.         val   = 0.0;
  969.         shown = 1.0;
  970.         maxval = 0.0;
  971.     }
  972.     else
  973.     {
  974.         val   = (float)value / (float)max;
  975.         shown = (float)size  / (float)max;
  976.         maxval = 1.0;
  977.     }
  978.     vim_XawScrollbarSetThumb(bottomScrollbar, val, shown, maxval);
  979. }
  980.  
  981.     Window
  982. gui_mch_get_wid()
  983. {
  984.     return( XtWindow(textArea) );
  985. }
  986.  
  987.     static void
  988. gui_athena_pullright_action(w, event, args, nargs)
  989.     Widget        w;
  990.     XEvent        *event;
  991.     String        *args;
  992.     Cardinal    *nargs;
  993. {
  994.     Widget        menuw;
  995.     Dimension    width, height;
  996.     char_u        *pullright_name;
  997.     Widget        popup;
  998.  
  999.     if (event->type != MotionNotify)
  1000.         return;
  1001.  
  1002.     /* Get the active entry for the current menu */
  1003.     if ((menuw = XawSimpleMenuGetActiveEntry(w)) == (Widget)NULL)
  1004.         return;
  1005.  
  1006.     XtVaGetValues(w,
  1007.         XtNwidth,    &width,
  1008.         XtNheight,    &height,
  1009.         NULL);
  1010.  
  1011.     if (event->xmotion.x >= width || event->xmotion.y >= height)
  1012.         return;
  1013.  
  1014.     /* We do the pull-off when the pointer is in the rightmost 1/4th */
  1015.     if (event->xmotion.x < (width * 3) / 4)
  1016.         return;
  1017.  
  1018.     pullright_name = strnsave(XtName(menuw), strlen(XtName(menuw)) +
  1019.                                                     strlen("-pullright"));
  1020.     strcat(pullright_name, "-pullright");
  1021.     popup = XtNameToWidget(w, pullright_name);
  1022.     vim_free(pullright_name);
  1023.  
  1024.     if (popup == (Widget)NULL)
  1025.         return;
  1026.  
  1027.     XtVaSetValues(popup,
  1028.         XtNx, event->xmotion.x_root,
  1029.         XtNy, event->xmotion.y_root - 7,
  1030.         NULL);
  1031.  
  1032.     XtPopup(popup, XtGrabExclusive);
  1033. }
  1034.